﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using PostSharp.Aspects;
using PostSharp.Aspects.Configuration;
using PostSharp.Extensibility;
using PostSharp.Reflection;
using System.Linq;

namespace BusinessFramework.AOP
{
#if !SILVERLIGHT
    [MulticastAttributeUsage(MulticastTargets.Class, Inheritance = MulticastInheritance.Strict)]
    [Serializable]
    public sealed class NotifyPropertyChangedAttribute : TypeLevelAspect, IAspectProvider
    {
        public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
        {
            var type = targetElement as Type;
            if (type==null) 
                return new AspectInstance[0];

            if (typeof(INotifyPropertyChanged).IsAssignableFrom(type))
                return new[] { new AspectInstance(targetElement, new AddNotifyPropertyChangedAttribute()) };
            else
                return new[] { new AspectInstance(targetElement, new ImplementNotifyPropertyChangedAttribute()) };
        }
    }

    [MulticastAttributeUsage(MulticastTargets.Class, Inheritance = MulticastInheritance.Strict)]
    public sealed class ExternalNotifyPropertyChangedAttribute : IExternalAspectImplementation
    {
        public IEnumerable<AspectInstance> ProvideImplementationAspects(object targetElement,
            ObjectConstruction aspectConstruction)
        {
            var type = targetElement as Type;
            if (type == null)
                return new AspectInstance[0];

            var implemented = type.GetInterfaces().Any(i => i.FullName == "System.ComponentModel.INotifyPropertyChanged");

            if (implemented)
                return new[]
                           {
                               new AspectInstance(targetElement, new ObjectConstruction(
                                                                     "BusinessFramework.AOP.AddNotifyPropertyChangedAttribute, BusinessFramework.AOP.SL"),
                                                  new AspectConfiguration())
                           };
            else
                return new[] {
                               new AspectInstance(targetElement, new ObjectConstruction(
                                                                     "BusinessFramework.AOP.ImplementNotifyPropertyChangedAttribute, BusinessFramework.AOP.SL"),
                                                  new AspectConfiguration())
                           };
        }
    }
#else
    [ExternalAspectConfiguration("BusinessFramework.AOP.ExternalNotifyPropertyChangedAttribute, BusinessFramework.AOP")]
    [MulticastAttributeUsage(MulticastTargets.Class | MulticastTargets.Struct, PersistMetaData = true)]
    public class NotifyPropertyChangedAttribute : ExternalAspect
    {
    }
#endif
}